/*
 * SipMessage.cpp
 *
 *  Created on: Dec 6, 2011
 *      Author: shaohong
 */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#include <stddef.h>
#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <iostream>

#include "SipMessage.h"
#include "SipDialog.h"
#include "SipHeader.h"
#include "SipServer.h"
#include "NmpsException.h"
#include "AppLogger.h"
#include "ParsingUtils.h"

using namespace std;

static AppLogger * logger = AppLogger::getInstance("SipMessage");

namespace nmps {


Hop::Hop(string ip, int port, Transport transport){
	this->ip = ip;
	this->port = port;
	this->transport = transport;
}

Hop::~Hop() {
}

string SipMessage::intoToString(int i){
    std::stringstream ss;
    std::string s;
    ss << i;
    s = ss.str();
	return s;
}

int SipMessage::stringToInt(string intStr){
	return atoi(intStr.c_str());
}

SipMessage::SipMessage() {
	// TODO Auto-generated constructor stub
	content = "";
}

SipMessage::~SipMessage() {
	// TODO Auto-generated destructor stub
}

// return the content of this sip message
string SipMessage::getContent(){
	return content;
}

// return the call-id of this sip message
string SipMessage::getCallID(){
	return headers[SipHeader::CALL_ID_HNAME];
}

// add the given header to the message
void SipMessage::addHeader(string headerName, string headerValue) {
	headers[headerName] = headerValue;
}

// given a header name, return the headerValue
string SipMessage::getHeader(string headerName){
	return headers[headerName];
}

string SipMessage::getContentType(){
	return headers[SipHeader::CONTENT_TYPE_HNAME];
}

void SipMessage::setContentType(string contentType){
	headers[SipHeader::CONTENT_TYPE_HNAME] = contentType;
}

void SipMessage::setContent(string contentType, string contentStr) {
	setContentType(contentType);
	int contentLength = contentStr.length();
	headers[SipHeader::CONTENT_LENGTH_HNAME] = intoToString(contentLength);
	content = contentStr;
}

// get the SipDialog associated with this SipMessage
SipDialog * SipMessage::getDialog() {
	return dialog;
}

void SipMessage::setSipDialog(SipDialog * sipDialog) {
	this->dialog = sipDialog;
}

bool SipMessage::hasTag(string& uriAndParams) {
	size_t tagStartPos = uriAndParams.find(";tag=");

	if (string::npos == tagStartPos) {
		return false;
	}

	return true;
}

void SipMessage::addTag(string& uriAndParams) {
	uriAndParams.append(";tag=nmps-2011");
}

//	v=0
//	o=shaohong 123456 654321 IN IP4 192.168.126.131
//	s=A conversation
//	c=IN IP4 192.168.126.131
//	t=0 0
//	m=audio 7078 RTP/AVP 111 110 0 3 8
//	a=rtpmap:111 speex/16000/1
//	a=rtpmap:110 speex/8000/1
//	a=rtpmap:0 PCMU/8000/1
//	a=rtpmap:3 GSM/8000/1
//	a=rtpmap:8 PCMA/8000/1
string SipMessage::extractRtpIP(string& offerSDP){
	size_t startPos;

	string connToken = string("c=IN IP4 ");
	startPos = offerSDP.find(connToken);
	if (startPos == string::npos) {
		return "";
	}
	// this is the start of the IP address
	startPos += connToken.length();

	size_t endPos = offerSDP.find('\x0d', startPos);
	return offerSDP.substr(startPos, endPos - startPos);

}

int SipMessage::extractRtpPort(string& offerSDP){
	string audioPortToken = string("m=audio ");
	size_t startPos = offerSDP.find(audioPortToken);
	if (startPos == string::npos) {
		return 0;
	}
	// this is the start of the audio Port part
	startPos += audioPortToken.length();

	size_t endPos = offerSDP.find(" ", startPos);
	string audioPortStr = offerSDP.substr(startPos, endPos - startPos);
	return stringToInt(audioPortStr);
}

/**
 * Parse the given received message into a SipMessage
 */
SipMessage * SipMessage::parseSipMessage(string receivedMessage){

	SipMessage * parseResult;

	// we'll look at the receivedMessage line by line and save the result in the parsed message
//	int nOfLines = ParsingUtils::getNumberOfLines(receivedMessage);

	stringstream ss(receivedMessage, ios_base::in);
	string currLine;

	// check the first line
	ParsingUtils::sipGetLine(ss, currLine);
	size_t tokenPos = currLine.find("SIP/2.0");
	if (tokenPos == string::npos){
		throw  NmpsException( "invalid SIP Message! first line doesn't contain \"SIP/2.0\"" );
	}

	if (tokenPos == 0){
		// TODO add the parsing of SipResponse
		// this is a SipResponse
		fprintf(stderr, "parsing SipResponse has not been implemented yet!");
		logger->error("parsing SipResponse has not been implemented yet!");
		exit(-1);

//		parseResult = new SipResponse();
//		int statusCode = extractStatusCode(currLine);
//		string reasonPhrase = extractReasonPhrase(currLine);
//		static_cast<SipResponse *>(parseResult)->setStatusCode(statusCode);
//		static_cast<SipResponse *>(parseResult)->setReasonPhrase(reasonPhrase);
	} else {
		// this is a SipRequest
		parseResult = new SipRequest();
		string method = ParsingUtils::extractMethod(currLine);
		string requestUri = ParsingUtils::extractRequestUri(currLine);
		dynamic_cast<SipRequest *>(parseResult)->setMethod(method);
		dynamic_cast<SipRequest *>(parseResult)->setRequestURI(requestUri);

	}

	// now we'll look at the second and later lines
	bool hasContent =false;
	while (!ss.eof()){
		ParsingUtils::sipGetLine(ss, currLine);

		if (ParsingUtils::isEmptyLine(currLine)){
			if (!hasContent) {
				// this is the end of the message;
				break;
			}

			// this is the separation line between header and content body
//			cerr << "contentPartStarted!" << endl;
			stringstream contentStrStream;

			//read the rests lines and save them into contentStringStream
			ParsingUtils::sipGetLine(ss, currLine);
			while (!ParsingUtils::isEmptyLine(currLine)) {
				contentStrStream << currLine << '\x0d' << '\x0a';
				ParsingUtils::sipGetLine(ss, currLine);
			}

			string contentStr = contentStrStream.str();
//			cerr << "contentStr is:\n" << contentStr<<endl;
			parseResult->setContent(parseResult->getContentType(), contentStr);
			break;
		}


//		fprintf(stderr, "currLine = %s\n", currLine.c_str());

		string headerName = ParsingUtils::extractHeaderName(currLine);
		string headerValue = ParsingUtils::extractHeaderValue(currLine);

		parseResult->addHeader(headerName, headerValue);

		if (0 == headerName.compare(SipHeader::CONTENT_TYPE_HNAME)) {
			hasContent = true;
//			fprintf(stderr, "has Content-Type header\n");
		}
	}

	return parseResult;

	//	SIP request looks like:
//	INVITE sip:francisco@bestel.com:55060 SIP/2.0
//	Via: SIP/2.0/UDP 200.57.7.195;branch=z9hG4bKff9b46fb055c0521cc24024da96cd290
//	Via: SIP/2.0/UDP 200.57.7.195:55061;branch=z9hG4bK291d90e31a47b225bd0ddff4353e9cc0
//	From: <sip:200.57.7.195:55061;user=phone>;tag=GR52RWG346-34
//	To: "francisco@bestel.com" <sip:francisco@bestel.com:55060>
//	Call-ID: 12013223@200.57.7.195
//	CSeq: 1 INVITE
//	Contact: <sip:200.57.7.195:5060>
//	Content-Type: application/sdp
//	Content-Length:   229
//
//	v=0
//	o=Clarent 120386 120387 IN IP4 200.57.7.196
//	s=Clarent C5CM
//	c=IN IP4 200.57.7.196
//	t=0 0
//	m=audio 40376 RTP/AVP 8 18 4 0
//	a=rtpmap:8 PCMA/8000
//	a=rtpmap:18 G729/8000
//	a=rtpmap:4 G723/8000
//	a=rtpmap:0 PCMU/8000
//	a=SendRecv


//	SIP response looks like this:
//	SIP/2.0 200 Ok
//	Via: SIP/2.0/UDP 200.57.7.195;branch=z9hG4bKff9b46fb055c0521cc24024da96cd290
//	Via: SIP/2.0/UDP 200.57.7.195:55061;branch=z9hG4bK291d90e31a47b225bd0ddff4353e9cc0
//	From: <sip:200.57.7.195:55061;user=phone>;tag=GR52RWG346-34
//	To: "francisco@bestel.com" <sip:francisco@bestel.com:55060>;tag=298852044
//	Contact: <sip:francisco@200.57.7.204:5061>
//	Call-ID: 12013223@200.57.7.195
//	CSeq: 1 INVITE
//	Content-Type: application/sdp
//	Server: X-Lite release 1103m
//	Content-Length: 298
//
//	v=0
//	o=francisco 13004970 13013442 IN IP4 200.57.7.204
//	s=X-Lite
//	c=IN IP4 200.57.7.204
//	t=0 0
//	m=audio 8000 RTP/AVP 8 0 3 98 97 101
//	a=rtpmap:0 pcmu/8000
//	a=rtpmap:8 pcma/8000
//	a=rtpmap:3 gsm/8000
//	a=rtpmap:98 iLBC/8000
//	a=rtpmap:97 speex/8000
//	a=rtpmap:101 telephone-event/8000
//	a=fmtp:101 0-15
//


}

string SipMessage::createAnswerSDP(string &offerSDP) {
	// The offer SDP from LinPhone looks like this:
//	v=0
//	o=shaohong 123456 654321 IN IP4 192.168.126.131
//	s=A conversation
//	c=IN IP4 192.168.126.131
//	t=0 0
//	m=audio 7078 RTP/AVP 111 110 0 3 8 101
//	a=rtpmap:111 speex/16000/1
//	a=rtpmap:110 speex/8000/1
//	a=rtpmap:0 PCMU/8000/1
//	a=rtpmap:3 GSM/8000/1
//	a=rtpmap:8 PCMA/8000/1
//	a=rtpmap:101 telephone-event/8000
//	a=fmtp:101 0-11
/**
 * So it's good that it doesn't have a m=video line and we don't need
 * to bother with create such answers
 */
	stringstream ss;
	ss << "v=0" << '\x0d' << '\x0a';
	ss << "o=radioStreamer 123456 654321 IN IP4 " << SipServer::getLocalInterfaceIP() <<'\x0d' << '\x0a';
	ss << "s=radioChannel" <<'\x0d' << '\x0a';
	ss << "c=IN IP4 " << SipServer::getLocalInterfaceIP() <<'\x0d' << '\x0a';
	ss << "t=0 0" <<'\x0d' << '\x0a';
	ss << "m=audio 8888 RTP/AVP 8" << '\x0d' << '\x0a';
	ss << "a=rtpmap:8 PCMA/8000/1" << '\x0d' << '\x0a';
	ss << "a=sendonly"  << '\x0d' << '\x0a';

	return ss.str();
}

} /* namespace nmps */
